/*
 * -------- classes of data types --------
 *
 * ATOMIC:
 * bools, null, integers, symbols, characters
 *
 * DATA:
 * strings
 *
 * COMPLEX:
 * boxes, conses, vectors, closures, records
 *
 *
 * -------- data layout of complex types --------
 *
 * box: skip=0
 * [SCM]
 * 
 * cons: skip=0
 * [SCM][SCM]
 *
 * vector: skip=1
 * [LEN][SCM][SCM]...[SCM]
 * 
 * closure: skip=2
 * [LEN][LBL][SCM][SCM]...[SCM]
 *
 * record: skip=2
 * [LEN][TAG][SCM]...[SCM]
 *
 *
 * Note: LEN is the number of SCM's, the total size of the object
 * is skips+LEN
 *
 *
 * -------- tagging --------
 *
 * The tags are organized into 3 sets:
 * [immediates] < [data] < [complex]
 * 
 * this enables us to quickly test what sort of
 * object we have
 *
 * further, for complex data the 2 bits of the
 * tag will give you the number of skips for
 * that object.
 *
 */

word gc_obj(word *o) {
  word tag, skips, len;
  word ptr, to_ptr;

  tag = TAG(*o);
  
  if(ATOMIC_TAG(tag)) {
    return *o;
  }
  else if(GC_MARK_TAG(tag)) {
    ptr = PTR(*o);
    return FROM_HEAP_REF(ptr);
  }
  else if(DATA_TAG(tag)) {
    ptr = PTR(*o);
    skips = FROM_HEAP_REF(ptr);
    len = 0;
  }
  else {
    ptr = PTR(*o);
    skip = SKIPS(*o);
    len = FROM_HEAP_REF(ptr);
  }

  // we need to allocate space in the "to" heap
  // - mark this object as dead so recursion wont loop
  //   or make spurious copies
  // - then copy the 'skips' amount of raw data across
  // - then copy each of the children into the space
  
  to_ptr = heap_alloc(skips + len);
  *o = OBJECT_TAG_PTR(tag_dead, to_ptr);
  
  memcpy(TO_HEAP(to_ptr), FROM_HEAP(ptr), skips*WORDSIZE);
  
  for(i = 0; i < len; i++) {
    TO_HEAP_REF(to_ptr + skip + i) = gc_obj(FROM_HEAP_REF(to_ptr + skip + i));
  }
  
  return OBJECT_TAG_PTR(tag, to_ptr);
}
